#ifndef VBO_H 
#define VBO_H
#include "Export.h"
#include <GL/glu.h>
#include <glew.h>
#include <iostream>
#define BUFFER_OFFSET(a) ((char*)NULL + (a))
#define STREAM  GL_STREAM_DRAW
#define DYNAMIC GL_DYNAMIC_DRAW
#define STATIC  GL_STATIC_DRAW
namespace glow {

  enum VBO_t { VERTEX, NORMAL, COLOR, TEXCOORD, EDGE_FLAG,INDEX };
  GLenum BUFFER_TYPE { GL_ARRAY_BUFFER, GL_ELEMENT_ARRAY_BUFFER };
  enum VBO_UPDATE_t { STREAM, DYNAMIC, STATIC};
  template< VBO_UPDATE_t U,VBO_t T , BUFFER_TYPE V >
    class SHARED VBO<U,T,V>{
  private:
    GLuint buf;
    bool firstpush;
    unsigned int VBO_SIZE;
  public:
    /** creer le VBO */
    VBO<U,T,V>(){
      
      firstpush=true;
      
      /* creation du VBO */
      glGenBuffers(1, &buf);
      
      /* on bind le buffer afin que glBufferData s'applique sur buf */
      glBindBuffer(V, buf);
     
    }
    /** Detruire le VBO */
    ~VBO<U,T,V>(){
      glDeleteBuffers(1, &buf);
    }
    /** Mettre des données dans le VBO*/
    void push(void * data, unsigned int size){
      
      VBO_SIZE=size;
	
      /* on considere qu'il n'est possible qye d'envoyer une fois des donnéesdans le VBO */
      if (firstpush){ /* c'est le premier push , il est autorise, on ne jette pas l'utilisateur */
	
	/*on alloue la place necessaire */
	glBufferData(V, VBO_SIZE, NULL, U);
	/*on donne l'emplacement des données */
	glBufferSubData(V,size,data);
	
	glBindBuffer(GL_ARRAY_BUFFER, 0);
	/*fin */ 
	
      }
      else {	  std::cout<<"erreur : VBO déja affecté"<<std::endl;
      }
    }
    
    
    
    /** Recuperer le type de données stockées dedans */
    
    GLenum getVBO_type() const {
      switch(T){
      case : VERTEX   : return GL_VERTEX_ARRAY;break; 
      case : NORMAL   : return GL_NORMAL_ARRAY;break;
      case : COLOR    : return GL_COLOR_ARRAY;break;
      case : TEXCOORD : return GL_TEXTURE_COORD_ARRAY;break;
      case : EDGE_FLAG: return GL_EDGE_FLAG_ARRAY;break;
      case : INDEX    : return GL_INDEX_ARRAY; 
      }
    }  
    /** recuperer la taille  du VBO */
    unsigned int getVBO_SIZE(){return VBO_SIZE;}
    /** recuperer l'id du VBO */
    GLuint getGLID() const {return buf;}
    
  };
  typedef VBO<U,T,GL_ARRAY_BUFFER>              VertexBuffer<T,U>;
  typedef VBO<U,INDEX,GL_ELEMENT_ARRAY_BUFFER>  IndexBuffer <T,U>;
}
#endif    
  
